package kotan.datastore.api;

import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import java.util.Map.Entry;

import com.google.appengine.api.datastore.KeyFactory;
import com.google.apphosting.api.ApiProxy;

/**
 * Convert utility between GAE API and Kotan API
 * @author shuji.w6e
 * @since 1.0
 */
public class DatastoreApiUtil {

    private static final Set<Class<?>> DEFAULT_TYPES = new HashSet<Class<?>>();
    static {
        DEFAULT_TYPES.add(Boolean.class);
        DEFAULT_TYPES.add(Integer.class);
        DEFAULT_TYPES.add(Long.class);
        DEFAULT_TYPES.add(Double.class);
        DEFAULT_TYPES.add(String.class);
        DEFAULT_TYPES.add(Date.class);
    }

    public static Entity convert(com.google.appengine.api.datastore.Entity aeEntity) {
        Entity entity = new Entity(convert(aeEntity.getKey()));
        for (Entry<String, Object> entry : aeEntity.getProperties().entrySet()) {
            Object org = entry.getValue();
            if (org == null) {
                entity.propertyMap.put(entry.getKey(), null);
                continue;
            }
            Class<?> clazz = org.getClass();
            Object value;
            if (DEFAULT_TYPES.contains(clazz)) {
                value = org;
            } else if (clazz == com.google.appengine.api.datastore.Key.class) {
                value = convert((com.google.appengine.api.datastore.Key) org);
            } else if (clazz == com.google.appengine.api.datastore.Text.class) {
                value = convert((com.google.appengine.api.datastore.Text) org);
            } else if (clazz == com.google.appengine.api.datastore.Blob.class) {
                value = convert((com.google.appengine.api.datastore.Blob) org);
            } else {
                throw new IllegalStateException("sorry, unsupported type yet: " + clazz);
            }
            entity.propertyMap.put(entry.getKey(), value);
        }
        return entity;
    }

    public static com.google.appengine.api.datastore.Entity convert(Entity entity) {
        if (entity == null) throw new IllegalArgumentException();
        if (entity.key == null) throw new IllegalArgumentException();
        com.google.appengine.api.datastore.Entity aeEntity =
            new com.google.appengine.api.datastore.Entity(convert(entity.key));
        for (Entry<String, Object> entry : entity.propertyMap.entrySet()) {
            Object org = entry.getValue();
            if (org == null) {
                aeEntity.setProperty(entry.getKey(), null);
                continue;
            }
            Class<?> clazz = org.getClass();
            Object value;
            if (DEFAULT_TYPES.contains(clazz)) {
                value = org;
            } else if (clazz == Key.class) {
                value = convert((Key) org);
            } else if (clazz == Text.class) {
                value = convert((Text) org);
            } else if (clazz == Blob.class) {
                value = convert((Blob) org);
            } else {
                throw new IllegalStateException("sorry, unsupported type yet: " + clazz);
            }
            aeEntity.setProperty(entry.getKey(), value);
        }
        return aeEntity;
    }

    /**
     * convert AppEngine Key to Kotan Key
     * @param aeKey
     * @return
     */
    public static Key convert(com.google.appengine.api.datastore.Key aeKey) {
        if (aeKey == null) return null;
        Key key = new Key();
        key.appId = ApiProxy.getCurrentEnvironment().getAppId();
        key.appIdNamespace = aeKey.getNamespace();
        key.parentKey = convert(aeKey.getParent());
        key.kind = aeKey.getKind();
        key.id = aeKey.getId();
        key.name = aeKey.getName();
        return key;
    }

    /**
     * convert Kotan Key to AppEngine Key.
     * @param key
     * @return
     */
    public static com.google.appengine.api.datastore.Key convert(Key key) {
        if (key == null) return null;
        if (0 < key.id) {
            if (key.parentKey == null) {
                return KeyFactory.createKey(key.kind, key.id);
            } else {
                return KeyFactory.createKey(convert(key.parentKey), key.kind, key.id);
            }
        } else {
            if (key.parentKey == null) {
                return KeyFactory.createKey(key.kind, key.name);
            } else {
                return KeyFactory.createKey(convert(key.parentKey), key.kind, key.name);
            }
        }
    }

    public static Text convert(com.google.appengine.api.datastore.Text aeText) {
        Text text = new Text();
        text.value = aeText.getValue();
        return text;
    }

    public static com.google.appengine.api.datastore.Text convert(Text text) {
        return new com.google.appengine.api.datastore.Text(text.value);
    }

    public static Blob convert(com.google.appengine.api.datastore.Blob aeBlob) {
        Blob blob = new Blob();
        blob.bytes = aeBlob.getBytes();
        return blob;
    }

    public static com.google.appengine.api.datastore.Blob convert(Blob blob) {
        return new com.google.appengine.api.datastore.Blob(blob.bytes);
    }

}
